<?php

namespace app\model\system;

use app\model\BaseModel;
use albert\traits\ModelTrait;
use Exception;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Route;

/**
 * 系统菜单 Model
 * Class SystemMenus
 * @package app\model\system
 */
class SystemMenus extends BaseModel
{
    use ModelTrait;

    /**
     * Params 修改器
     * Author: Albert3306
     * Date: 2021/4/26
     * @param $value
     * @return false|string
     */
    public function setParamsAttr($value)
    {
        $value = $value ? explode('/', $value) : [];
        $params = array_chunk($value, 2);
        $data = [];
        foreach ($params as $param) {
            if (isset($param[0]) && isset($param[1])) $data[$param[0]] = $param[1];
        }
        return json_encode($data);
    }

    /**
     * Controller 获取器
     * Author: Albert3306
     * Date: 2021/4/26
     * @param $value
     * @return string
     */
    protected function setControllerAttr($value): string
    {
        return lcfirst($value);
    }

    /**
     * Params 获取器
     * Author: Albert3306
     * Date: 2021/4/26
     * @param $_value
     * @return mixed
     */
    public function getParamsAttr($_value)
    {
        return json_decode($_value, true);
    }

    /**
     * PID 获取器
     * Author: Albert3306
     * Date: 2021/4/26
     * @param $value
     * @return mixed|string
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getPidAttr($value)
    {
        return !$value ? '顶级' : self::get($value)['name'];
    }

    /**
     * 查询条件设置
     * Author: Albert3306
     * Date: 2021/4/28
     * @param $where
     * @param null $model
     * @return SystemMenus|mixed
     */
    public static function initWhere($where, $model = null)
    {
        $model = $model ?? new self;
        if (isset($where['ids']) && $where['ids'] !== '') {
            $model = $model->whereIn('id', $where['ids']);
        }
        if (isset($where['pid']) && $where['pid'] !== '') {
            $model = $model->where('pid', $where['pid']);
        }
        if (isset($where['is_show']) && $where['is_show'] !== '') {
            $model = $model->where('is_show', $where['is_show']);
        }
        if (isset($where['action']) && $where['action'] !== '') {
            $model = $model->where('action', $where['action']);
        }
        if (isset($where['module']) && $where['module'] !== '') {
            $model = $model->where('module', $where['module']);
        }
        if (isset($where['controller']) && $where['controller'] !== '') {
            $model = $model->where('controller', $where['controller']);
        }
        if (isset($where['keywords']) && $where['keywords'] !== '') {
            $model = $model->whereLike('id|pid|name', '%' . $where['keywords'] . '%');
        }
        return $model;
    }

    /**
     * @param $action
     * @param $controller
     * @param $module
     * @param $route
     * @return string
     */
    public static function getAuthName($action, $controller, $module, $route): string
    {
        return strtolower($module . '/' . $controller . '/' . $action . '/' . self::paramStr($route));
    }

    /**
     * @param $params
     * @return string
     */
    public static function paramStr($params): string
    {
        if (!is_array($params)) $params = json_decode($params, true) ?: [];
        $p = [];
        foreach ($params as $key => $param) {
            $p[] = $key;
            $p[] = $param;
        }
        return implode('/', $p);
    }

    /**
     * 获取菜单列表
     * Author: Albert3306
     * Date: 2021/4/26
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     * @throws Exception
     */
    public static function menuList(): array
    {
        $menusList = self::initWhere(['is_show' => 1])->order('sort DESC')->select();
        return self::tidyMenuTier($menusList, true);
    }

    /**
     * 整理菜单栏
     * Author: Albert3306
     * Date: 2021/4/26
     * @param $menusList
     * @param false $adminFilter
     * @param int $pid
     * @param array $navList
     * @return array
     * @throws Exception
     */
    public static function tidyMenuTier($menusList, bool $adminFilter = false, int $pid = 0, array $navList = []): array
    {
        static $allAuth = null;
        static $adminAuth = null;
        if ($allAuth === null) $allAuth = $adminFilter == true ? SystemRole::getAllAuth() : []; // 所有的菜单
        if ($adminAuth === null) $adminAuth = $adminFilter == true ? SystemAdmin::activeAdminAuthOrFail() : []; // 当前登录用户的菜单
        foreach ($menusList as $k => $menu) {
            $menu = $menu->getData();
            if ($menu['pid'] == $pid) {
                unset($menusList[$k]);
                $params = json_decode($menu['params'], true); // 获取参数
                $authName = self::getAuthName($menu['action'], $menu['controller'], $menu['module'], $params); // 按钮链接
                if ($pid != 0 && $adminFilter && in_array($authName, $allAuth) && (!in_array($authName, $adminAuth) || !array_key_exists($menu['id'], $adminAuth))) continue;
                $menu['child'] = self::tidyMenuTier($menusList, $adminFilter, $menu['id']);
                if ($pid != 0 && !count($menu['child']) && !$menu['controller'] && !$menu['action']) continue;
                $menu['url'] = !count($menu['child']) ? Route::buildUrl($menu['route'], $params) : 'javascript:void(0);';
                if ($pid == 0 && !count($menu['child'])) continue;
                $navList[] = $menu;
            }
        }
        return $navList;
    }

    /**
     * 获取访问栏目名称
     * Author: Albert3306
     * Date: 2021/4/26
     * @param $action
     * @param $controller
     * @param $module
     * @param array $route
     * @return mixed
     */
    public static function getVisitName($action, $controller, $module, array $route = [])
    {
        $params = json_encode($route);
        return self::initWhere(['action' => $action, 'module' => lcfirst($module), 'controller' => lcfirst($controller)])
            ->where("params = '$params' OR params = '[]'")
            ->order('id DESC')
            ->value('name');
    }

    /**
     * 获取 LayUI 列表数据 - 无分页
     * Author: Albert3306
     * Date: 2021/4/28
     * @param $params
     * @param string $field
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public static function getLayUIAllList($params, string $field = 'id,name,pid,module,controller,action,route,is_show'): array
    {
        $model = self::initWhere($params);
        $count = $model->count();
        $data = $model->field($field)->order('sort DESC')->select()->toArray();
        return compact('count', 'data');
    }

    /**
     * 删除菜单
     * Author: Albert3306
     * Date: 2021/5/1
     * @param $id
     * @return bool
     */
    public static function delMenu($id): bool
    {
        if (self::initWhere(['pid' => $id])->count())
            return self::setErrorInfo('请先删除改菜单下的子菜单!');
        return self::del($id);
    }

    /**
     * 获取权限列表
     * Author: Albert3306
     * Date: 2021/5/1
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     * @throws Exception
     */
    public static function ruleList(): array
    {
        $ruleList = self::initWhere([])->order('sort DESC')->select();
        return self::tidyMenuTier($ruleList, false);
    }

    /**
     * 获取角色（可多个）权限列表
     * Author: Albert3306
     * Date: 2021/5/1
     * @param $rules
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     * @throws Exception
     */
    public static function rolesByRuleList($rules): array
    {
        $res = SystemRole::initWhere(['ids' => $rules])->field('GROUP_CONCAT(rules) as ids')->find();
        $ruleList = self::initWhere(['ids' => $res['ids']])->whereOr('pid', 0)->order('sort DESC')->select();
        return self::tidyMenuTier($ruleList, false);
    }
}